{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "    <div class=\"bk-root\">\n",
       "        <a href=\"https://bokeh.pydata.org\" target=\"_blank\" class=\"bk-logo bk-logo-small bk-logo-notebook\"></a>\n",
       "        <span id=\"1001\">Loading BokehJS ...</span>\n",
       "    </div>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/javascript": [
       "\n",
       "(function(root) {\n",
       "  function now() {\n",
       "    return new Date();\n",
       "  }\n",
       "\n",
       "  var force = true;\n",
       "\n",
       "  if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n",
       "    root._bokeh_onload_callbacks = [];\n",
       "    root._bokeh_is_loading = undefined;\n",
       "  }\n",
       "\n",
       "  var JS_MIME_TYPE = 'application/javascript';\n",
       "  var HTML_MIME_TYPE = 'text/html';\n",
       "  var EXEC_MIME_TYPE = 'application/vnd.bokehjs_exec.v0+json';\n",
       "  var CLASS_NAME = 'output_bokeh rendered_html';\n",
       "\n",
       "  /**\n",
       "   * Render data to the DOM node\n",
       "   */\n",
       "  function render(props, node) {\n",
       "    var script = document.createElement(\"script\");\n",
       "    node.appendChild(script);\n",
       "  }\n",
       "\n",
       "  /**\n",
       "   * Handle when an output is cleared or removed\n",
       "   */\n",
       "  function handleClearOutput(event, handle) {\n",
       "    var cell = handle.cell;\n",
       "\n",
       "    var id = cell.output_area._bokeh_element_id;\n",
       "    var server_id = cell.output_area._bokeh_server_id;\n",
       "    // Clean up Bokeh references\n",
       "    if (id != null && id in Bokeh.index) {\n",
       "      Bokeh.index[id].model.document.clear();\n",
       "      delete Bokeh.index[id];\n",
       "    }\n",
       "\n",
       "    if (server_id !== undefined) {\n",
       "      // Clean up Bokeh references\n",
       "      var cmd = \"from bokeh.io.state import curstate; print(curstate().uuid_to_server['\" + server_id + \"'].get_sessions()[0].document.roots[0]._id)\";\n",
       "      cell.notebook.kernel.execute(cmd, {\n",
       "        iopub: {\n",
       "          output: function(msg) {\n",
       "            var id = msg.content.text.trim();\n",
       "            if (id in Bokeh.index) {\n",
       "              Bokeh.index[id].model.document.clear();\n",
       "              delete Bokeh.index[id];\n",
       "            }\n",
       "          }\n",
       "        }\n",
       "      });\n",
       "      // Destroy server and session\n",
       "      var cmd = \"import bokeh.io.notebook as ion; ion.destroy_server('\" + server_id + \"')\";\n",
       "      cell.notebook.kernel.execute(cmd);\n",
       "    }\n",
       "  }\n",
       "\n",
       "  /**\n",
       "   * Handle when a new output is added\n",
       "   */\n",
       "  function handleAddOutput(event, handle) {\n",
       "    var output_area = handle.output_area;\n",
       "    var output = handle.output;\n",
       "\n",
       "    // limit handleAddOutput to display_data with EXEC_MIME_TYPE content only\n",
       "    if ((output.output_type != \"display_data\") || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n",
       "      return\n",
       "    }\n",
       "\n",
       "    var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n",
       "\n",
       "    if (output.metadata[EXEC_MIME_TYPE][\"id\"] !== undefined) {\n",
       "      toinsert[toinsert.length - 1].firstChild.textContent = output.data[JS_MIME_TYPE];\n",
       "      // store reference to embed id on output_area\n",
       "      output_area._bokeh_element_id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n",
       "    }\n",
       "    if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n",
       "      var bk_div = document.createElement(\"div\");\n",
       "      bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n",
       "      var script_attrs = bk_div.children[0].attributes;\n",
       "      for (var i = 0; i < script_attrs.length; i++) {\n",
       "        toinsert[toinsert.length - 1].firstChild.setAttribute(script_attrs[i].name, script_attrs[i].value);\n",
       "      }\n",
       "      // store reference to server id on output_area\n",
       "      output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n",
       "    }\n",
       "  }\n",
       "\n",
       "  function register_renderer(events, OutputArea) {\n",
       "\n",
       "    function append_mime(data, metadata, element) {\n",
       "      // create a DOM node to render to\n",
       "      var toinsert = this.create_output_subarea(\n",
       "        metadata,\n",
       "        CLASS_NAME,\n",
       "        EXEC_MIME_TYPE\n",
       "      );\n",
       "      this.keyboard_manager.register_events(toinsert);\n",
       "      // Render to node\n",
       "      var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n",
       "      render(props, toinsert[toinsert.length - 1]);\n",
       "      element.append(toinsert);\n",
       "      return toinsert\n",
       "    }\n",
       "\n",
       "    /* Handle when an output is cleared or removed */\n",
       "    events.on('clear_output.CodeCell', handleClearOutput);\n",
       "    events.on('delete.Cell', handleClearOutput);\n",
       "\n",
       "    /* Handle when a new output is added */\n",
       "    events.on('output_added.OutputArea', handleAddOutput);\n",
       "\n",
       "    /**\n",
       "     * Register the mime type and append_mime function with output_area\n",
       "     */\n",
       "    OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n",
       "      /* Is output safe? */\n",
       "      safe: true,\n",
       "      /* Index of renderer in `output_area.display_order` */\n",
       "      index: 0\n",
       "    });\n",
       "  }\n",
       "\n",
       "  // register the mime type if in Jupyter Notebook environment and previously unregistered\n",
       "  if (root.Jupyter !== undefined) {\n",
       "    var events = require('base/js/events');\n",
       "    var OutputArea = require('notebook/js/outputarea').OutputArea;\n",
       "\n",
       "    if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n",
       "      register_renderer(events, OutputArea);\n",
       "    }\n",
       "  }\n",
       "\n",
       "  \n",
       "  if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n",
       "    root._bokeh_timeout = Date.now() + 5000;\n",
       "    root._bokeh_failed_load = false;\n",
       "  }\n",
       "\n",
       "  var NB_LOAD_WARNING = {'data': {'text/html':\n",
       "     \"<div style='background-color: #fdd'>\\n\"+\n",
       "     \"<p>\\n\"+\n",
       "     \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n",
       "     \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n",
       "     \"</p>\\n\"+\n",
       "     \"<ul>\\n\"+\n",
       "     \"<li>re-rerun `output_notebook()` to attempt to load from CDN again, or</li>\\n\"+\n",
       "     \"<li>use INLINE resources instead, as so:</li>\\n\"+\n",
       "     \"</ul>\\n\"+\n",
       "     \"<code>\\n\"+\n",
       "     \"from bokeh.resources import INLINE\\n\"+\n",
       "     \"output_notebook(resources=INLINE)\\n\"+\n",
       "     \"</code>\\n\"+\n",
       "     \"</div>\"}};\n",
       "\n",
       "  function display_loaded() {\n",
       "    var el = document.getElementById(\"1001\");\n",
       "    if (el != null) {\n",
       "      el.textContent = \"BokehJS is loading...\";\n",
       "    }\n",
       "    if (root.Bokeh !== undefined) {\n",
       "      if (el != null) {\n",
       "        el.textContent = \"BokehJS \" + root.Bokeh.version + \" successfully loaded.\";\n",
       "      }\n",
       "    } else if (Date.now() < root._bokeh_timeout) {\n",
       "      setTimeout(display_loaded, 100)\n",
       "    }\n",
       "  }\n",
       "\n",
       "\n",
       "  function run_callbacks() {\n",
       "    try {\n",
       "      root._bokeh_onload_callbacks.forEach(function(callback) {\n",
       "        if (callback != null)\n",
       "          callback();\n",
       "      });\n",
       "    } finally {\n",
       "      delete root._bokeh_onload_callbacks\n",
       "    }\n",
       "    console.debug(\"Bokeh: all callbacks have finished\");\n",
       "  }\n",
       "\n",
       "  function load_libs(css_urls, js_urls, callback) {\n",
       "    if (css_urls == null) css_urls = [];\n",
       "    if (js_urls == null) js_urls = [];\n",
       "\n",
       "    root._bokeh_onload_callbacks.push(callback);\n",
       "    if (root._bokeh_is_loading > 0) {\n",
       "      console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n",
       "      return null;\n",
       "    }\n",
       "    if (js_urls == null || js_urls.length === 0) {\n",
       "      run_callbacks();\n",
       "      return null;\n",
       "    }\n",
       "    console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n",
       "    root._bokeh_is_loading = css_urls.length + js_urls.length;\n",
       "\n",
       "    function on_load() {\n",
       "      root._bokeh_is_loading--;\n",
       "      if (root._bokeh_is_loading === 0) {\n",
       "        console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n",
       "        run_callbacks()\n",
       "      }\n",
       "    }\n",
       "\n",
       "    function on_error() {\n",
       "      console.error(\"failed to load \" + url);\n",
       "    }\n",
       "\n",
       "    for (var i = 0; i < css_urls.length; i++) {\n",
       "      var url = css_urls[i];\n",
       "      const element = document.createElement(\"link\");\n",
       "      element.onload = on_load;\n",
       "      element.onerror = on_error;\n",
       "      element.rel = \"stylesheet\";\n",
       "      element.type = \"text/css\";\n",
       "      element.href = url;\n",
       "      console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n",
       "      document.body.appendChild(element);\n",
       "    }\n",
       "\n",
       "    for (var i = 0; i < js_urls.length; i++) {\n",
       "      var url = js_urls[i];\n",
       "      var element = document.createElement('script');\n",
       "      element.onload = on_load;\n",
       "      element.onerror = on_error;\n",
       "      element.async = false;\n",
       "      element.src = url;\n",
       "      console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n",
       "      document.head.appendChild(element);\n",
       "    }\n",
       "  };var element = document.getElementById(\"1001\");\n",
       "  if (element == null) {\n",
       "    console.error(\"Bokeh: ERROR: autoload.js configured with elementid '1001' but no matching script tag was found. \")\n",
       "    return false;\n",
       "  }\n",
       "\n",
       "  function inject_raw_css(css) {\n",
       "    const element = document.createElement(\"style\");\n",
       "    element.appendChild(document.createTextNode(css));\n",
       "    document.body.appendChild(element);\n",
       "  }\n",
       "\n",
       "  var js_urls = [\"https://cdn.pydata.org/bokeh/release/bokeh-1.1.0.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-widgets-1.1.0.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-tables-1.1.0.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-gl-1.1.0.min.js\"];\n",
       "  var css_urls = [\"https://cdn.pydata.org/bokeh/release/bokeh-1.1.0.min.css\", \"https://cdn.pydata.org/bokeh/release/bokeh-widgets-1.1.0.min.css\", \"https://cdn.pydata.org/bokeh/release/bokeh-tables-1.1.0.min.css\"];\n",
       "\n",
       "  var inline_js = [\n",
       "    function(Bokeh) {\n",
       "      Bokeh.set_log_level(\"info\");\n",
       "    },\n",
       "    \n",
       "    function(Bokeh) {\n",
       "      \n",
       "    },\n",
       "    function(Bokeh) {} // ensure no trailing comma for IE\n",
       "  ];\n",
       "\n",
       "  function run_inline_js() {\n",
       "    \n",
       "    if ((root.Bokeh !== undefined) || (force === true)) {\n",
       "      for (var i = 0; i < inline_js.length; i++) {\n",
       "        inline_js[i].call(root, root.Bokeh);\n",
       "      }if (force === true) {\n",
       "        display_loaded();\n",
       "      }} else if (Date.now() < root._bokeh_timeout) {\n",
       "      setTimeout(run_inline_js, 100);\n",
       "    } else if (!root._bokeh_failed_load) {\n",
       "      console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n",
       "      root._bokeh_failed_load = true;\n",
       "    } else if (force !== true) {\n",
       "      var cell = $(document.getElementById(\"1001\")).parents('.cell').data().cell;\n",
       "      cell.output_area.append_execute_result(NB_LOAD_WARNING)\n",
       "    }\n",
       "\n",
       "  }\n",
       "\n",
       "  if (root._bokeh_is_loading === 0) {\n",
       "    console.debug(\"Bokeh: BokehJS loaded, going straight to plotting\");\n",
       "    run_inline_js();\n",
       "  } else {\n",
       "    load_libs(css_urls, js_urls, function() {\n",
       "      console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n",
       "      run_inline_js();\n",
       "    });\n",
       "  }\n",
       "}(window));"
      ],
      "application/vnd.bokehjs_load.v0+json": "\n(function(root) {\n  function now() {\n    return new Date();\n  }\n\n  var force = true;\n\n  if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n    root._bokeh_onload_callbacks = [];\n    root._bokeh_is_loading = undefined;\n  }\n\n  \n\n  \n  if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n    root._bokeh_timeout = Date.now() + 5000;\n    root._bokeh_failed_load = false;\n  }\n\n  var NB_LOAD_WARNING = {'data': {'text/html':\n     \"<div style='background-color: #fdd'>\\n\"+\n     \"<p>\\n\"+\n     \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n     \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n     \"</p>\\n\"+\n     \"<ul>\\n\"+\n     \"<li>re-rerun `output_notebook()` to attempt to load from CDN again, or</li>\\n\"+\n     \"<li>use INLINE resources instead, as so:</li>\\n\"+\n     \"</ul>\\n\"+\n     \"<code>\\n\"+\n     \"from bokeh.resources import INLINE\\n\"+\n     \"output_notebook(resources=INLINE)\\n\"+\n     \"</code>\\n\"+\n     \"</div>\"}};\n\n  function display_loaded() {\n    var el = document.getElementById(\"1001\");\n    if (el != null) {\n      el.textContent = \"BokehJS is loading...\";\n    }\n    if (root.Bokeh !== undefined) {\n      if (el != null) {\n        el.textContent = \"BokehJS \" + root.Bokeh.version + \" successfully loaded.\";\n      }\n    } else if (Date.now() < root._bokeh_timeout) {\n      setTimeout(display_loaded, 100)\n    }\n  }\n\n\n  function run_callbacks() {\n    try {\n      root._bokeh_onload_callbacks.forEach(function(callback) {\n        if (callback != null)\n          callback();\n      });\n    } finally {\n      delete root._bokeh_onload_callbacks\n    }\n    console.debug(\"Bokeh: all callbacks have finished\");\n  }\n\n  function load_libs(css_urls, js_urls, callback) {\n    if (css_urls == null) css_urls = [];\n    if (js_urls == null) js_urls = [];\n\n    root._bokeh_onload_callbacks.push(callback);\n    if (root._bokeh_is_loading > 0) {\n      console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n      return null;\n    }\n    if (js_urls == null || js_urls.length === 0) {\n      run_callbacks();\n      return null;\n    }\n    console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n    root._bokeh_is_loading = css_urls.length + js_urls.length;\n\n    function on_load() {\n      root._bokeh_is_loading--;\n      if (root._bokeh_is_loading === 0) {\n        console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n        run_callbacks()\n      }\n    }\n\n    function on_error() {\n      console.error(\"failed to load \" + url);\n    }\n\n    for (var i = 0; i < css_urls.length; i++) {\n      var url = css_urls[i];\n      const element = document.createElement(\"link\");\n      element.onload = on_load;\n      element.onerror = on_error;\n      element.rel = \"stylesheet\";\n      element.type = \"text/css\";\n      element.href = url;\n      console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n      document.body.appendChild(element);\n    }\n\n    for (var i = 0; i < js_urls.length; i++) {\n      var url = js_urls[i];\n      var element = document.createElement('script');\n      element.onload = on_load;\n      element.onerror = on_error;\n      element.async = false;\n      element.src = url;\n      console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n      document.head.appendChild(element);\n    }\n  };var element = document.getElementById(\"1001\");\n  if (element == null) {\n    console.error(\"Bokeh: ERROR: autoload.js configured with elementid '1001' but no matching script tag was found. \")\n    return false;\n  }\n\n  function inject_raw_css(css) {\n    const element = document.createElement(\"style\");\n    element.appendChild(document.createTextNode(css));\n    document.body.appendChild(element);\n  }\n\n  var js_urls = [\"https://cdn.pydata.org/bokeh/release/bokeh-1.1.0.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-widgets-1.1.0.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-tables-1.1.0.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-gl-1.1.0.min.js\"];\n  var css_urls = [\"https://cdn.pydata.org/bokeh/release/bokeh-1.1.0.min.css\", \"https://cdn.pydata.org/bokeh/release/bokeh-widgets-1.1.0.min.css\", \"https://cdn.pydata.org/bokeh/release/bokeh-tables-1.1.0.min.css\"];\n\n  var inline_js = [\n    function(Bokeh) {\n      Bokeh.set_log_level(\"info\");\n    },\n    \n    function(Bokeh) {\n      \n    },\n    function(Bokeh) {} // ensure no trailing comma for IE\n  ];\n\n  function run_inline_js() {\n    \n    if ((root.Bokeh !== undefined) || (force === true)) {\n      for (var i = 0; i < inline_js.length; i++) {\n        inline_js[i].call(root, root.Bokeh);\n      }if (force === true) {\n        display_loaded();\n      }} else if (Date.now() < root._bokeh_timeout) {\n      setTimeout(run_inline_js, 100);\n    } else if (!root._bokeh_failed_load) {\n      console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n      root._bokeh_failed_load = true;\n    } else if (force !== true) {\n      var cell = $(document.getElementById(\"1001\")).parents('.cell').data().cell;\n      cell.output_area.append_execute_result(NB_LOAD_WARNING)\n    }\n\n  }\n\n  if (root._bokeh_is_loading === 0) {\n    console.debug(\"Bokeh: BokehJS loaded, going straight to plotting\");\n    run_inline_js();\n  } else {\n    load_libs(css_urls, js_urls, function() {\n      console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n      run_inline_js();\n    });\n  }\n}(window));"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "from bokeh.plotting import figure, show, output_notebook\n",
    "from bokeh.layouts import gridplot\n",
    "output_notebook()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Object `curdoc` not found.\n"
     ]
    }
   ],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from bokeh.themes import built_in_themes\n",
    "from bokeh.io import curdoc\n",
    "curdoc().theme = 'dark_minimal'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'\\n<div class=\"bk-root\" id=\"9c63edd1-d65b-4d7f-bf04-32cfeddd54c7\" data-root-id=\"1944\"></div>'"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from math import pi\n",
    "import pandas as pd\n",
    "from bokeh.palettes import Category20c\n",
    "from bokeh.transform import cumsum\n",
    "# 数据\n",
    "x = {\n",
    "    'United States': 157,\n",
    "    'United Kingdom': 93,\n",
    "    'Japan': 89,\n",
    "    'China': 63,\n",
    "    'Germany': 44,\n",
    "    'India': 42,\n",
    "    'Italy': 40,\n",
    "    'Australia': 35,\n",
    "    'Brazil': 32,\n",
    "    'France': 31,\n",
    "    'Taiwan': 31,\n",
    "    'Spain': 29\n",
    "}\n",
    "data = pd.Series(x).reset_index(name='value').rename(columns={'index':'country'})\n",
    "data['angle'] = data['value']/data['value'].sum() * 2*pi\n",
    "data['color'] = Category20c[len(x)]\n",
    "# 画布\n",
    "p = figure(plot_height=350, title=\"Pie Chart\",\n",
    "#            toolbar_location=None,\n",
    "           tools=\"save,hover\", tooltips=\"@country: @value\", x_range=(-0.5, 1.0), sizing_mode=\"scale_width\")\n",
    "# 绘图\n",
    "p.wedge(x=0, y=1, radius=0.4,\n",
    "        start_angle=cumsum('angle', include_zero=True), end_angle=cumsum('angle'),\n",
    "        line_color=\"white\", fill_color='color', legend='country', source=data)\n",
    "# 其他\n",
    "p.axis.axis_label=None\n",
    "p.axis.visible=False\n",
    "p.grid.grid_line_color = None\n",
    "# 显示\n",
    "# show(p)\n",
    "# html组件1\n",
    "from bokeh.embed import components\n",
    "script_01, div_01 = components(p)\n",
    "div_01"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'\\n<div class=\"bk-root\" id=\"92f91216-85ed-47f5-b5a1-63b43258d96b\" data-root-id=\"2020\"></div>'"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 画布\n",
    "p = figure(plot_height=350, title=\"Donut Chart\", \n",
    "#            toolbar_location=None,\n",
    "           tools=\"save,hover\", tooltips=\"国家@country: 数值@value\", sizing_mode=\"scale_width\")  # 已支持中文,鼠标悬停饼图显示数据\n",
    "# 绘图\n",
    "p.annular_wedge(x=0, y=1, outer_radius=0.4,inner_radius=0.3, \n",
    "        # use cumsum to cumulatively sum the values for start and end angles\n",
    "        start_angle=cumsum('angle', include_zero=True), end_angle=cumsum('angle'),\n",
    "        line_color=\"white\", fill_color='color', legend='country', source=data)\n",
    "# 其他\n",
    "p.axis.axis_label=None\n",
    "p.axis.visible=False\n",
    "p.grid.grid_line_color = None\n",
    "# 显示\n",
    "# show(p)\n",
    "# html组件2\n",
    "from bokeh.embed import components\n",
    "script_02, div_02 = components(p)\n",
    "div_02"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'\\n<div class=\"bk-root\" id=\"e63251db-da80-4dc8-99ee-02c63a21672f\" data-root-id=\"2097\"></div>'"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from bokeh.models import ColumnDataSource, NumeralTickFormatter, SingleIntervalTicker\n",
    "from bokeh.sampledata.us_marriages_divorces import data\n",
    "# 数据\n",
    "data = data.interpolate(method='linear', axis=0).ffill().bfill()\n",
    "source = ColumnDataSource(data=dict(\n",
    "    year=data.Year.values,\n",
    "    marriages=data.Marriages_per_1000.values,\n",
    "    divorces=data.Divorces_per_1000.values,\n",
    "))\n",
    "# 工具条\n",
    "TOOLS = 'pan,wheel_zoom,box_zoom,reset,save'\n",
    "# 画布\n",
    "p = figure(tools=TOOLS,  plot_height=300,\n",
    "           tooltips='<font face=\"Arial\" size=\"3\">@$name{0.0} $name per 1,000 people in @year</font>', sizing_mode=\"scale_width\")\n",
    "# 其他自定义属性\n",
    "p.hover.mode = 'vline'\n",
    "p.xaxis.ticker = SingleIntervalTicker(interval=10, num_minor_ticks=0)\n",
    "p.yaxis.formatter = NumeralTickFormatter(format='0.0a')\n",
    "p.yaxis.axis_label = '# per 1,000 people'\n",
    "p.title.text = '144 years of marriage and divorce in the U.S.'\n",
    "# 绘图\n",
    "p.line('year', 'marriages', color='#1f77b4', line_width=3, source=source, name=\"marriages\")\n",
    "p.line('year', 'divorces', color='#ff7f0e', line_width=3, source=source, name=\"divorces\")\n",
    "# 显示\n",
    "# show(p)\n",
    "# html组件3\n",
    "from bokeh.embed import components\n",
    "script_03, div_03 = components(p)\n",
    "div_03"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'\\n<div class=\"bk-root\" id=\"4b354329-160a-4f27-9291-3b17d4b07e2a\" data-root-id=\"2181\"></div>'"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from math import pi\n",
    "import pandas as pd\n",
    "from bokeh.models import LinearColorMapper, BasicTicker, PrintfTickFormatter, ColorBar\n",
    "from bokeh.sampledata.unemployment1948 import data\n",
    "# 数据\n",
    "data['Year'] = data['Year'].astype(str)\n",
    "data = data.set_index('Year')\n",
    "data.drop('Annual', axis=1, inplace=True)\n",
    "data.columns.name = 'Month'\n",
    "years = list(data.index)\n",
    "months = list(data.columns)\n",
    "df = pd.DataFrame(data.stack(), columns=['rate']).reset_index()\n",
    "# 配色\n",
    "colors = [\"#75968f\", \"#a5bab7\", \"#c9d9d3\", \"#e2e2e2\", \"#dfccce\", \"#ddb7b1\", \"#cc7878\", \"#933b41\", \"#550b1d\"]\n",
    "mapper = LinearColorMapper(palette=colors, low=df.rate.min(), high=df.rate.max())\n",
    "# 工具条\n",
    "TOOLS = \"hover,save,pan,box_zoom,reset,wheel_zoom\"\n",
    "# 画布\n",
    "p = figure(title=\"US Unemployment ({0} - {1})\".format(years[0], years[-1]),\n",
    "           x_range=years, y_range=list(reversed(months)),\n",
    "           x_axis_location=\"above\", plot_width=900, plot_height=400,\n",
    "           tools=TOOLS, toolbar_location='below',\n",
    "           tooltips=[('date', '@Month @Year'), ('rate', '@rate%')], sizing_mode=\"scale_width\")\n",
    "# 其他\n",
    "p.grid.grid_line_color = None\n",
    "p.axis.axis_line_color = None\n",
    "p.axis.major_tick_line_color = None\n",
    "p.axis.major_label_text_font_size = \"5pt\"\n",
    "p.axis.major_label_standoff = 0\n",
    "p.xaxis.major_label_orientation = pi / 3\n",
    "# 绘图\n",
    "p.rect(x=\"Year\", y=\"Month\", width=1, height=1,\n",
    "       source=df,\n",
    "       fill_color={'field': 'rate', 'transform': mapper},\n",
    "       line_color=None)\n",
    "# 色值条\n",
    "color_bar = ColorBar(color_mapper=mapper, major_label_text_font_size=\"5pt\",\n",
    "                     ticker=BasicTicker(desired_num_ticks=len(colors)),\n",
    "                     formatter=PrintfTickFormatter(format=\"%d%%\"),\n",
    "                     label_standoff=6, border_line_color=None, location=(0, 0))\n",
    "p.add_layout(color_bar, 'right')\n",
    "# 显示\n",
    "# html组件4\n",
    "from bokeh.embed import components\n",
    "script_04, div_04 = components(p)\n",
    "div_04"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'\\n<div class=\"bk-root\" id=\"7311636e-a824-4fcc-88cc-dcf2736ada59\" data-root-id=\"2480\"></div>'"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import networkx as nx\n",
    "from bokeh.io import show, curdoc\n",
    "from bokeh.layouts import Row, Column\n",
    "from bokeh.models import Plot, Range1d, MultiLine, Circle, HoverTool, TapTool, BoxSelectTool\n",
    "from bokeh.models.graphs import from_networkx, NodesAndLinkedEdges, EdgesAndLinkedNodes\n",
    "from bokeh.palettes import Spectral4\n",
    "G=nx.karate_club_graph()\n",
    "def create_graph(layout_func, inspection_policy=None, selection_policy=None, **kwargs):\n",
    "\n",
    "    plot = Plot(plot_width=400, plot_height=400,\n",
    "                x_range=Range1d(-1.1,1.1), y_range=Range1d(-1.1,1.1))\n",
    "    graph_renderer = from_networkx(G, layout_func, **kwargs)\n",
    "\n",
    "    graph_renderer.node_renderer.glyph = Circle(size=15, fill_color=Spectral4[0])\n",
    "    graph_renderer.node_renderer.selection_glyph = Circle(size=15, fill_color=Spectral4[2])\n",
    "    graph_renderer.node_renderer.hover_glyph = Circle(size=15, fill_color=Spectral4[1])\n",
    "\n",
    "    graph_renderer.edge_renderer.glyph = MultiLine(line_color=\"#CCCCCC\", line_alpha=0.8, line_width=5)\n",
    "    graph_renderer.edge_renderer.selection_glyph = MultiLine(line_color=Spectral4[2], line_width=5)\n",
    "    graph_renderer.edge_renderer.hover_glyph = MultiLine(line_color=Spectral4[1], line_width=5)\n",
    "\n",
    "    graph_renderer.inspection_policy = inspection_policy\n",
    "    graph_renderer.selection_policy = selection_policy\n",
    "\n",
    "    plot.renderers.append(graph_renderer)\n",
    "\n",
    "    return plot\n",
    "\n",
    "plot_1 = create_graph(nx.circular_layout, inspection_policy=NodesAndLinkedEdges(), scale=1, center=(0,0))\n",
    "plot_1.title.text = \"Circular Layout (NodesAndLinkedEdges inspection policy)\"\n",
    "plot_1.add_tools(HoverTool(tooltips=None))\n",
    "\n",
    "plot_2 = create_graph(nx.spring_layout, selection_policy=NodesAndLinkedEdges(), scale=2, center=(0,0))\n",
    "plot_2.title.text = \"Spring Layout (NodesAndLinkedEdges selection policy)\"\n",
    "plot_2.add_tools(TapTool(), BoxSelectTool())\n",
    "\n",
    "plot_3 = create_graph(nx.random_layout, inspection_policy=EdgesAndLinkedNodes(), center=(0,0))\n",
    "plot_3.title.text = \"Random Layout (EdgesAndLinkedNodes inspection policy)\"\n",
    "plot_3.add_tools(HoverTool(tooltips=None))\n",
    "\n",
    "plot_4 = create_graph(nx.fruchterman_reingold_layout, selection_policy=EdgesAndLinkedNodes(), scale=2, center=(0,0), dim=2)\n",
    "plot_4.title.text = \"FR Layout (EdgesAndLinkedNodes selection policy)\"\n",
    "plot_4.add_tools(TapTool())\n",
    "\n",
    "layout = Column(Row(plot_1, plot_2), Row(plot_3, plot_4))\n",
    "# show(layout)\n",
    "# html组件5\n",
    "from bokeh.embed import components\n",
    "script_05, div_05 = components(layout)\n",
    "div_05"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# html源码\n",
    "html = '''\n",
    "<!DOCTYPE html>\n",
    "<html>\n",
    "<head>\n",
    "    <meta charset=\"utf-8\"> \n",
    "    <title>Bokeh embed Bootstrap 实例</title>\n",
    "    <link rel=\"stylesheet\" href=\"https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css\">\n",
    "    <script src=\"https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js\"></script>\n",
    "    <script src=\"https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js\"></script>\n",
    "    \n",
    "    <link rel=\"stylesheet\" href=\"https://cdn.pydata.org/bokeh/release/bokeh-1.1.0.min.css\">\n",
    "    <link rel=\"stylesheet\" href=\"https://cdn.pydata.org/bokeh/release/bokeh-widgets-1.1.0.min.css\">   \n",
    "    <script src=\"https://cdn.pydata.org/bokeh/release/bokeh-1.1.0.min.js\"></script>\n",
    "    <script src=\"https://cdn.pydata.org/bokeh/release/bokeh-widgets-1.1.0.min.js\"></script>\n",
    "</head>\n",
    "<body style='background-color:black'>\n",
    "<div style='margin:0 15px 0 15px'>\n",
    "    <div class=\"row\">\n",
    "        <div class=\"col-md-6\">\n",
    "        {div_01}\n",
    "        </div>\n",
    "        <div class=\"col-md-6\">\n",
    "        {div_02}\n",
    "        </div>\n",
    "    </div>\n",
    "    <div class=\"row\">\n",
    "        <div class=\"col-md-6\">\n",
    "            {div_03}\n",
    "       </div>\n",
    "        <div class=\"col-md-6\"> \n",
    "            {div_04}\n",
    "        </div>\n",
    "    </div>\n",
    "    <div class=\"row\">\n",
    "        <div class=\"col-md-6 col-md-offset-3\">\n",
    "        {div_05}\n",
    "        </div>\n",
    "    </div>\n",
    "</div>\n",
    "{script_01}\n",
    "{script_02}\n",
    "{script_03}\n",
    "{script_04}\n",
    "{script_05}\n",
    "</body>\n",
    "</html>'''.format(div_01=div_01,script_01=script_01,div_02=div_02,script_02=script_02,\n",
    "                  div_03=div_03,script_03=script_03,div_04=div_04,script_04=script_04,\n",
    "                  div_05=div_05,script_05=script_05)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "with open(\"Bokeh embed Bootstrap2.html\", \"w\", encoding='utf-8') as f:\n",
    "    f.write(html)# 保存为html文件"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda root]",
   "language": "python",
   "name": "conda-root-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.2"
  },
  "toc": {
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": "block",
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
